<!-- 代码已包含 CSS：使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
<template>
	<div class="min-h-screen bg-slate-50">
		<!-- 不可点击的遮罩层 -->
		<div v-if="appInfo.enable==false" class="fixed inset-0 bg-gray-500 bg-opacity-50  z-40"></div>
		<!-- 左侧导航 -->
		<div class="fixed left-0 top-0 h-full  bg-white shadow-lg backdrop-blur-sm z-30 transition-all duration-300 "
			:class="{
      '-translate-x-full': (isSidebarHidden && isPC)||isSidebarHidden ,
      'w-64':isPC}
      ">
			<!-- 左侧导航 -->

			<!-- 搜索框 -->
			<div class="p-4">
				<div class="relative">
					<input type="text" v-model="keywords" @keyup.enter="searchHistory" placeholder="搜索历史对话..." class="w-full pl-10 pr-4 py-2.5 bg-slate-50/50 rounded-xl text-sm border-none
                  focus:ring-2 focus:ring-blue-100/50 transition-all keywords-div">
					<i class="fas fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
				</div>
			</div>
			<!-- 对话历史列表 -->
			<div class="chat-list-div">
				<div class="overflow-y-auto h-[calc(100vh-80px)] ">
					<div v-for="(chat,index)  in chats" :key="chat.id" :class="{'bg-blue-50': chat.id === activeChatId}"
						@click="activeChatId = chat.id" @scroll="handleSessionScroll"
						@mouseenter="showDeleteButton(index)" @mouseleave="handleMouseLeave($event, index)"
						class="group px-4 py-4 hover:bg-slate-50 cursor-pointer transition-colors border-b border-slate-100 last:border-b-0">
						<div class="flex items-start justify-between gap-1">
							<div class="flex flex-col min-w-0">
								<span class="text-sm text-gray-700 font-medium mb-1 truncate">{{ chat.name }}</span>
								<span class="text-xs text-gray-400">{{ chat.createTime }}</span>
							</div>
							<span :class="{ 'hidden':!showDelete[index] }" v-if="isPC">
								<jb-btn icon="" text   type="error" circle :confirmText="'确认删除该会话？'"
									:url="`/aiAppSession/delete/${chat.id}`" @success="handleDeleteChat(index)"
									@open="openConfirm(index)" @cancel="handleCancel(index)"
									@close="closeConfirm(index)">
                                    <jb-icon icon="ri:delete-bin-line"></jb-icon>
                                </jb-btn>
							</span>
							<span v-else>
								<jb-btn :icon="Icons.DELETE" text type="error" circle :confirmText="'确认删除该会话？'"
									color="#c3c3c3" :url="`/aiAppSession/delete/${chat.id}`"
									@success="handleDeleteChat(index)"></jb-btn>
							</span>

						</div>
					</div>
				</div>
			</div>
			<div class="absolute -right-10 top-1 md:top-4">
				<button @click="toggleSidebar"
					class="!rounded-button w-8 h-8 flex items-center justify-center text-gray-900 hover:text-gray-600 bg-white transition-all">
					<i class="fas" :class="isSidebarHidden? 'fa-chevron-right' : 'fa-chevron-left'"></i>
				</button>
			</div>
		</div>
		<!-- 主聊天区域 -->
		<div class=" h-screen flex flex-col bg-slate-50/50 transition-all duration-300" :class="{
       'ml-64':!isSidebarHidden && isPC,
       'ml-0': isSidebarHidden ||!isPC,
       'w-[calc(100%-16rem)]':!isSidebarHidden && isPC, // 当侧边栏显示时，预留侧边栏宽度
       'w-full': isSidebarHidden ||!isPC // 当侧边栏隐藏或屏幕小于1024px时，全宽
     }">
			<!-- 遮罩层-->
			<div v-if="!isSidebarHidden && !isPC" class="fixed  inset-0 bg-gray-500 bg-opacity-50  z-10"
				@click="toggleSidebar"></div>
			<!-- 顶部栏 -->
			<div
				class="min-h-28 md:min-h-32 pt-8 pb-6 md:pt-4 md:py-4 border-b bg-white backdrop-blur-sm flex items-center justify-between px-4 md:px-16 relative shadow-sm">
				<div class="absolute top-1 md:top-4 right-4 flex gap-2">
					<button @click="handleAddChat"
						class="!rounded-button w-8 h-8 flex items-center justify-center text-slate-500 hover:text-slate-700 bg-slate-100 hover:bg-slate-200 transition-all">
						<n-popover trigger="hover">
							<template #trigger>
								<i class="fas fa-plus text-sm"></i>
							</template>
							<span>添加新会话</span>
						</n-popover>
					</button>

					<n-popconfirm @positive-click="handlePositiveClick" @negative-click="handleNegativeClick">
						<template #trigger>
							<button
								class="!rounded-button w-8 h-8 flex items-center justify-center text-gray-500 hover:text-gray-700 bg-slate-100 hover:bg-gray-200 transition-all">
								<!--								<n-icon class="fa-trash-alt text-sm">-->
								<!--									<SyncOutline />-->
								<!--								</n-icon>-->
								<jb-icon icon="ri:delete-bin-line"></jb-icon>
							</button>
						</template>
						确定要清空当前聊天记录么?
					</n-popconfirm>


				</div>
				<div class="max-w-full flex-1 flex flex-col md:flex-row items-center justify-center gap-3 md:gap-6">
					<div class="w-12 h-12 md:w-16 md:h-16 rounded-2xl flex items-center justify-center shrink-0">
						<img :src="appInfo.appLogo" alt="Logo" class="w-full h-full object-contain">
					</div>
					<div class="flex flex-col items-center md:items-start  overflow-hidden max-w-full">
						<h2
							class="text-2xl md:text-3xl font-bold bg-gradient-to-r from-[#4f46e5] via-[#4338ca] to-[#3730a3] bg-clip-text text-transparent tracking-wider text-center md:text-left whitespace-nowrap text-ellipsis overflow-hidden max-w-full">
							{{ appInfo.name }}
						</h2>
						<div class="flex items-center gap-4 md:mt-2 max-w-full">
							<p
								class="text-gray-500 font-medium whitespace-nowrap text-ellipsis overflow-hidden max-w-full">
								{{ appInfo.briefInfo }}
							</p>
						</div>
					</div>
				</div>
			</div>
			<!-- 对话内容区 -->
            <div v-if="!activeChatId"
                 style="display: flex; justify-content: center;align-items: center;flex:1;font-size: 36px;font-weight: 500;color:#d5d5d5">
                请先创建或选择一个会话
            </div>
			<div v-show="activeChatId" class="chat_panel" style="position: relative" ref="chatContainer"></div>
		</div>
	</div>
</template>
<script lang="ts" setup>
	import { JBoltApi } from "@/service/request/index.js";
	import { useMessage } from 'naive-ui'
	import {
		ref,
		onMounted,
		onBeforeMount,
		reactive,
		watch,
		onActivated,
		onDeactivated
	} from 'vue';
	import {
		Icons
	} from '@/constants'
	import {
		useRoute
	} from "vue-router";
	import {
		useWebSocketStore
	} from "@/stores/websocket.js";
	import { storeToRefs } from "pinia";
	import markdownit from 'markdown-it'
	import AiChat from '@/components/_builtin/jb-ai-chat/index.js'


	const route = useRoute()
	const appSn = route.params.appSn;
    const appId = ref(null)
	const chats = ref([]);
	const activeChatId = ref(null);
	const message = useMessage()
	const showDelete = ref({})// 控制删除按钮显示的状态
	const confirmOpen = ref({}) // 控制询问框是否打开的状态
	const currentChat = ref({
		id: '',
		name: '',
		hasMsg: false,
		config: {
			llmConfig: {
				systemRole: ''
			}
		}
	})

	//默认当前的app对象
	const appInfo = ref({
		name: '',
		userAvatar: '',
		showAvatar: false,
		assistantAvatar: '',
		appLogo: '',
		briefInfo: '',
		enable: false
	})


	const isSidebarHidden = ref(false);
	const isPC = ref(true);
	const window = ref(globalThis.window);
	// 监听窗口大小变化
	const handleResize = () => {
		isPC.value = window.value.innerWidth >= 1024;
		if (!isPC.value) {
			isSidebarHidden.value = true;
		}
	};
	const webSocketStore = storeToRefs(useWebSocketStore())
	const chatContainer = ref(null);
	const chatInstance = ref(null);
	const chatState = ref({
		pageSize: 20,
		hasMore: true,
	})

	const md = markdownit({
		html: true,
		breaks: true,
		linkify: true,
		typographer: true
	});
	const showDeleteButton = (index) => {
		if (!confirmOpen.value[index]) {
			showDelete.value[index] = true;
		}
	};

	const handleMouseLeave = (event, index) => {
		const target = event.relatedTarget;
		const isMovingToPopover = target && (target.classList.contains('n-popover') || target.classList.contains('n-popover-arrow'));
		if (target && !event.currentTarget.contains(target) && !confirmOpen.value[index] && !isMovingToPopover) {
			showDelete.value[index] = false;
		}
	};


	const openConfirm = (index) => {
		confirmOpen.value[index] = true;
	};

	const closeConfirm = (index) => {
		confirmOpen.value[index] = false;
		showDelete.value[index] = false;
	};
	const handleCancel = (index) => {
		// 隐藏删除按钮
		showDelete.value[index] = false;
		// 重置确认框打开状态
		confirmOpen.value[index] = false;
	};


	function handlePositiveClick() {
		JBoltApi.get(`/aiAppMessage/delete/${activeChatId.value}`).then(res => {
			message.success('聊天记录清除成功');
			loadChatInstance()
		})
	}

	function handleNegativeClick() {
		message.info('已取消')
	}

	// const _chatContainer = ref<HTMLElement | null>(null);
	const keywords = ref('');

	watch(() => webSocketStore.ws.value, () => {
		console.debug("websock重连")
		if (chatInstance.value) {
			chatInstance.value.updateWebSocket(webSocketStore.ws.value)
		}
	})

	watch(() => chatContainer.value, (newV) => {
		console.debug("chatContainer watch...")
		//dom初始化好了
		if (newV && activeChatId.value && !chatInstance.value) {
			loadChatInstance()
		}
	})
	watch(() => activeChatId.value, (newV) => {
		if (newV) {
			if (chatInstance.value) {
				chatInstance.value.destroy();
			}
			JBoltApi.get(`/aiAppSession/getById/${activeChatId.value}`).then(res => {
				currentChat.value = {
					...res.result.data,
					hasMsg: false
				}
			})
			if (chatContainer.value) {
				chatState.value = {
					pageSize: 20,
					hasMore: true
				}
				loadChatInstance()
			}
			if (!isPC.value) {
				isSidebarHidden.value = true;
			}
		}

	})

	function loadChatInstance() {
		//初始化aichat
		chatInstance.value = new AiChat(chatContainer.value, {
			websocketInstance: webSocketStore.ws.value,
			app: appId.value,
			sessionId: activeChatId.value,
			global: null,
			showAvatar: appInfo.value.showAvatar ?? true,
			userAvatar: appInfo.value.userAvatar ?? "",
			assistantAvatar: appInfo.value.assistantAvatar ?? "",
			onMsgReceive: (data) => {
			},
			onMsgSend: (msg) => {
				if (currentChat.value.hasMsg == false) {
					handleUpdateSessionName(currentChat.value.id, msg.data.content.text);
				}
			},
			onMsgToDelete: async (id) => {
				console.debug("删除消息", id)
				let {
					result
				} = await JBoltApi.get(`/aiAppMessage/delMsgById/${id}`)
				if (result.code == 0) {
					message.success("删除成功");
					return true;
				} else {
					message.error("删除失败");
					return false;
				}
			},
			onMarkdownRender: (markdown) => {
				return md.render(markdown);
			},
			onHistoryLoad: async (startId, global) => {
				if (chatState.value.hasMore == false) return;
				let {
					result
				} = await JBoltApi.get('/aiAppMessage/getListByPage', {
					sessionId: activeChatId.value,
					startId,
					pageSize: chatState.value.pageSize,
				})

				let {
					list,
					totalPage
				} = result.data
				chatState.value.hasMore = chatState.value.pageSize == list?.length;
				// console.error("加载历史记录开始", list)
				if (!list || !list.length) {
					// console.error(currentChat.value.hasMsg)
					return false;
				}
				// messages.value = [...messages.value, ...list]
				// console.debug("加载历史记录完成...", list)
				currentChat.value.hasMsg = true;
				return list.map(item => {
					return {
						id: item.id,
						flag: item.role == "user" ? item.id : item.linkId,
						data: {
							role: item.role,
							format: item.role == 'assistant' ? "markdown" : "",
							content: {
								text: item.content,
							},
							reference: item.reference,
							errorMsg: item.errorMsg,
						},
						createTime: item.createTime
					}
				})
			}
		})
	}

	// 处理滚动事件
	function handleSessionScroll(e) {
		const {
			scrollHeight,
			scrollTop,
			clientHeight
		} = e.target;
		// 距离底部100px时加载更多
		if (scrollHeight - scrollTop - clientHeight < 100 && !chatPageState.loading && chatPageState.hasMore) {
			loadChatList(false);
		}
	}

	//更新session
	function handleUpdateSessionName(sessionId, msg) {
		var name = msg.substring(0, 20);
		JBoltApi.post('/aiAppSession/update', {
			name: name,
			id: sessionId,
			appId: appId.value
		}).then(() => {
			const itemToUpdate = chats.value.find(item => item.id === sessionId);
			if (itemToUpdate) {
				itemToUpdate.name = name;
			}
		});
	}

	//获取app
	function getApp() {
		JBoltApi.tryGet(`/aiApp/getBySn/${appSn}`).then((res) => {

			appInfo.value = res.data;
            appId.value = appInfo.value.id;
			appInfo.value.showAvatar = res.data.config.uiConfig.showAvatar;
			//如果没有传logo,就用默认JBoltAI头像
			if (res.data.config.uiConfig.appLogo != undefined && res.data.config.uiConfig.appLogo != '') {
				appInfo.value.appLogo = res.data.config.uiConfig.appLogo;
			} else {
				appInfo.value.appLogo = 'https://static.jbolt.cn/website/jboltai_logo_icon.png';
			}
			appInfo.value.assistantAvatar = res.data.config.uiConfig.assistantAvatar;
			appInfo.value.userAvatar = res.data.config.uiConfig.userAvatar;
			if (!appInfo.value.enable) { //应用已发布
				message.error("应用未发布，请先发布应用");
			}
            // 页面加载时设置标题
            document.title = appInfo.value.name;
            loadChatList(true);
		});
	}


	//重新刷新session列表
	function resetChatList() {
		chatPageState.startId = null;
		chatPageState.hasMore = true;
		chatPageState.loading = false;
		chats.value = [];
	}

	//新建session
	function handleAddChat() {
		JBoltApi.post('/aiAppSession/add', {
			name: '新的会话',
			appId: appId.value, //内置appId
		}).then(() => {
			resetChatList();
			loadChatList(true);
		});
	}

	//关键词搜索session
	const searchHistory = () => {
		resetChatList()
		loadChatList(true);
	};

	const toggleSidebar = () => {
		isSidebarHidden.value = !isSidebarHidden.value;
	};


	const chatPageState = reactive({
		pageSize: 20,
		startId: null,
		hasMore: true,
		loading: false,
	});

	//删除session对象
	function handleDeleteChat(index) {
		if (activeChatId.value == chats.value[index].id) {
			activeChatId.value = null;
		}
		chats.value.splice(index, 1);
		// 隐藏删除按钮
		showDelete.value[index] = false;
		// 重置确认框打开状态
		confirmOpen.value[index] = false;
	}

	//加载session列表
	async function loadChatList(isFirst) {
		// console.error("调用")
		if (chatPageState.loading || chatPageState.hasMore == false) return;
		// console.error("调用22")
		chatPageState.loading = true;
		try {
			const {
				result
			} = await JBoltApi.get('/aiAppSession/getListByPage', {
				pageSize: chatPageState.pageSize,
				startId: chatPageState.startId,
				keywords: keywords.value,
				appId: appId.value, //内置应用
			});
			let {
				list,
				totalPage
			} = result.data;

			list = list ?? [];
			chatPageState.hasMore = list.length == chatPageState.pageSize;

			chatPageState.startId = list[list.length - 1]?.id;
			chats.value.push(...list)

			if (isFirst) {
				activeChatId.value = chats.value[0]?.id
			}
		} catch (error) {
			console.error('加载聊天列表失败:', error);
		} finally {
			chatPageState.loading = false;
		}
	}

	onMounted(() => {
		getApp();
		// scrollToBottom();



	});
	onBeforeMount(() => {
		// 初始化时检查窗口大小
		handleResize();
		// 添加窗口大小变化监听器
		window.value.addEventListener('resize', handleResize);
		if (chatInstance.value) {
			chatInstance.value.destroy()
		}
	});
	onActivated(() => {
		if (!chatInstance.value && activeChatId.value) {
			chatState.value.hasMore = true
			loadChatInstance()
		}
		console.error("aiChat组件被激活,当前被选中的id:" + activeChatId.value)
	})
	onDeactivated(() => {
		if (chatInstance.value) {
			chatInstance.value.destroy()
			chatInstance.value = null;
		}
	})
</script>
<style scoped>
	.chat-container::-webkit-scrollbar {
		width: 6px;
	}

	.chat-container::-webkit-scrollbar-track {
		background: transparent;
	}

	.chat-container::-webkit-scrollbar-thumb {
		background-color: rgba(156, 163, 175, 0.5);
		border-radius: 3px;
	}

	input[type="range"] {
		-webkit-appearance: none;
		width: 100%;
		height: 4px;
		border-radius: 2px;
		background: #e5e7eb;
		outline: none;
	}

	input[type="range"]::-webkit-slider-thumb {
		-webkit-appearance: none;
		appearance: none;
		width: 16px;
		height: 16px;
		border-radius: 50%;
		background: #4f46e5;
		cursor: pointer;
		transition: background .2s ease-in-out;
	}

	input[type="range"]::-webkit-slider-thumb:hover {
		background: #4338ca;
	}

	textarea:focus {
		outline: none;
		box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.1);
	}

	[data-v-8aed1f8e] {
		width: 100%;
		margin: 0 auto;
	}

	@keyframes fadeIn {
		from {
			opacity: 0;
			transform: translateY(10px);
		}

		to {
			opacity: 1;
			transform: translateY(0);
		}
	}

	@keyframes fadeOut {
		from {
			opacity: 1;
			transform: translateY(0);
		}

		to {
			opacity: 0;
			transform: translateY(10px);
		}
	}

	.animate-fade-in {
		animation: fadeIn 0.3s ease-out forwards;
	}

	.animate-fade-out {
		animation: fadeOut 0.3s ease-out forwards;
	}

	.chat_panel {
		flex: 1;
		overflow: hidden;
	}

	/* 滚动条样式 */
	/* 定义滚动条整体的宽度和轨道的背景颜色 */
	.chat-list-div ::-webkit-scrollbar {
		width: 5px;
		/* 对于垂直滚动条的宽度 */
		height: 5px;
		/* 对于水平滚动条的高度，可选 */
	}

	.chat-list-div ::-webkit-scrollbar {
		display: none;
	}

	.chat-list-div:hover ::-webkit-scrollbar {
		display: block;
	}




	/* 定义滚动条轨道的样式 */
	.chat-list-div ::-webkit-scrollbar-track {
		background-color: rgba(0, 0, 0, 0.05);
		/* 轨道的颜色 */
		border-radius: 5px;
		/* 轨道的圆角 */
	}

	/* 定义滚动条滑块的样式 */
	.chat-list-div ::-webkit-scrollbar-thumb {
		background-color: rgba(0, 0, 0, 0.05);
		/* 滑块的颜色 */
		border-radius: 5px;
		/* 滑块的圆角 */
		transition: background-color 0.2s ease;
		/* 可选：滑块颜色过渡效果 */
	}

	/* 当滑块不被鼠标悬停时的样式 */
	.chat-list-div ::-webkit-scrollbar-thumb:window-inactive {
		background-color: rgba(0, 0, 0, 0.05);
		/* 非活动状态下的滑块颜色 */
	}

	/* Firefox 的滚动条轨道 */
	scrollbar {
		-moz-appearance: none;
		/* 禁用默认样式 */
		width: 5px;
		/* 设置宽度 */
	}

	/* Firefox 的滚动条滑块 */
	scrollbar-thumb {
		background-color: rgba(0, 0, 0, 0.05);
		/* 设置颜色 */
		border-radius: 5px;
		/* 圆角 */
		transition: background-color 0.2s ease;
		/* 过渡效果 */
	}

	/* 当滑块被hover时 */
	scrollbar-thumb:hover {
		background-color: rgba(0, 0, 0, 0.05);
		/* 更深的颜色 */
	}

	.keywords-div {
		outline: none;
		/* 移除默认的outline */
		box-shadow: 0 2px 10px 3px rgb(0 0 0 / 5%), inset 0 1px 2px rgba(255, 255, 255, 0.1);
		;
		/* 自定义聚焦时的效果 */
	}

	.keywords-div:focus {
		/* 移除默认的outline */
		box-shadow: 0 2px 10px 3px rgba(0, 0, 0, 0.2), inset 0 1px 2px rgba(255, 255, 255, 0.1);
		;
		/* 自定义聚焦时的效果 */
	}
</style>